﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace GISCore.Geometry.Partition
{
    public enum OverlayOp { Union, Intersection, Difference, Same, Touch, Within, Contain, Nothing, Xor };

    [Serializable]
    public class UniformGrid : IPartitionable
    {
        //for grids
        private int _rowCount;
        private int _columnCount;

        /* lower bounding box */
        private Point _lowerBoundingBox;
        private List<PostPolygon> _postPolygons = new List<PostPolygon>();
        //private Cell[,] _cells; //= new Cell[Constants.getRowCount(), Constants.getColumnCount()];

        public UniformGrid(int rowCount, int colCount)
        {
            if (rowCount < 1)
                throw new ArgumentException("Row Count must be a positive integer!");
            if (colCount < 1)
                throw new ArgumentException("Column Count must be a positive integer!");

            _rowCount = rowCount;
            _columnCount = colCount;
            //_cells = new Cell[_rowCount, _columnCount];
        }

        public IDictionary<int,ICellable> Partition(Layer layer1, Layer layer2)
        {
            var cellidToCell = new Dictionary<int, ICellable>();
            var cellWidthCellHeight = _calculateDimensions(layer1, layer2);
            List<Layer> layers = new List<Layer>() { layer1, layer2 };

            IEnumerable<Polygon> polygons = from layer in layers
                                            where layer != null
                                            from poly in layer.GetPolygons()
                                            where poly != null
                                            select poly;

            foreach (var poly in polygons)
            {
                foreach (var line in poly.getLines())
                {
                    _partitionLinesByGrids(line, cellWidthCellHeight.Item1, cellWidthCellHeight.Item2, cellidToCell);
                }

                /* partition holes */
                IEnumerable<Line> holelines = from hole in poly.holes
                                              where hole != null
                                              from line in hole.getLines()
                                              select line;

                foreach (var line in holelines)
                {
                    _partitionLinesByGrids(line, cellWidthCellHeight.Item1, cellWidthCellHeight.Item2, cellidToCell);
                }
            }

            // there was a bug when returning it as IDictionary<int,ICellable>;
            return cellidToCell ;//as Dictionary<int,ICellable>;
        }

        private void _partitionLinesByGrids(Line line, double cellWidth, double cellHeight, Dictionary<int, ICellable> cellDictionary)
        {
            HashSet<GridIntersectPoint> gridPointSet = new HashSet<GridIntersectPoint>();
            Point startPoint = line.Start;
            Point endPoint = line.End;

            /* Need to maintain swap information since the order of lines added to the cell
               is getting changed when end points are swapped.
               isXCordSwap = true denotes if startX and endX got swapped
               isYCordSwap = true denotes if startY and endY got swapped
            */
            bool isXCordSwapped = false;
         
            double startXGridCord;
            double endXGridCord;

            /* refactored method */
            getStartEndGridXCordinate(cellWidth, startPoint, endPoint, out startXGridCord, 
                out endXGridCord,out isXCordSwapped);

            /* Horizontal Sweep */
            GridIntersectPoint gridIntersectPoint;
            //Finding intersection between Ax + By + C = 0 and x = a;
            //solve by substituting for X

            //for lines of the form y = constant
            if (line.getACoefficient() == 0)
            {
                for (double xCord = startXGridCord; xCord <= endXGridCord; xCord = xCord + cellWidth)
                {
                    gridIntersectPoint = new GridIntersectPoint(xCord, -line.getCCoefficient());
                    /* Add the parent line to the grid point , useful in merging phase */
                    gridIntersectPoint.setLine(line);
                    gridPointSet.Add(gridIntersectPoint);
                }
            }
            else if (0 != line.getBCoefficient())
            {
                double y;
                for (double xCord = startXGridCord; xCord <= endXGridCord; xCord = xCord + cellWidth)
                {
                    y = (-line.getCCoefficient() - line.getACoefficient() * xCord) / line.getBCoefficient();

                    gridIntersectPoint = new GridIntersectPoint(xCord, y);
                    /* Add the parent line to the grid point , useful in merging phase */
                    gridIntersectPoint.setLine(line);
                    //intersection point is (xCord,y)
                    //add to list
                    gridPointSet.Add(gridIntersectPoint);
                }
            }

            Point startPt = line.Start;
            Point endPt = line.End;

            bool isYCordSwapped = false;
           
            double startYGridCord;
            double endYGridCord;
            
            /* refactored method */
            getStartEndGridYCordinate(cellHeight, startPt, endPt, out startYGridCord, 
                out endYGridCord,out isYCordSwapped);
            /* Vertical Sweep*/

            //finding intersection between Ax + By + C = 0 and y = b;
            //solve by substituting for Y
            double x;
            if (0 == line.getBCoefficient())
            {
                for (double yCord = startYGridCord; yCord <= endYGridCord; yCord = yCord + cellHeight)
                {
                    gridIntersectPoint = new GridIntersectPoint(-line.getCCoefficient(), yCord);
                    /* Add the parent line to the grid point , useful in merging phase */
                    gridIntersectPoint.setLine(line);

                    gridPointSet.Add(gridIntersectPoint);
                    //line.addPoint(gridIntersectPoint);
                }
            }
            else
            {
                /* avoid cases when A = 0 since y = b and Ax + By + C = 0 are collinear in this case
                  , so no grid points*/
                if (0 != line.getACoefficient())
                {
                    for (double yCord = startYGridCord; yCord <= endYGridCord; yCord = yCord + cellHeight)
                    {
                        x = (-line.getCCoefficient() - line.getBCoefficient() * yCord) / line.getACoefficient();
                        //intersection point is (x,YCord)
                        //add point to the list
                        gridIntersectPoint = new GridIntersectPoint(x, yCord);
                        /* Add the parent line to the grid point , useful in merging phase */
                        gridIntersectPoint.setLine(line);

                        gridPointSet.Add(gridIntersectPoint);
                        //line.addPoint(gridIntersectPoint);
                    }
                }
            }
            /*the line is fully  contained inside the cell */
            if (0 == gridPointSet.Count())
            {
                _addGridLineToCell(line, cellDictionary, isXCordSwapped, isYCordSwapped, cellWidth, cellHeight);
            }
            else
            {
                
                //sorting based on x-coordinates
                List<GridIntersectPoint> gridPoints = gridPointSet.ToList();
                gridPoints.Sort();

                List<GridIntersectPoint> originalGridPts = clonePts(gridPoints);
                /*
                   remove the start point and end point if they
                   are same as one of the grid point to remove
                   redundant point and to fix merging bug
                */
                gridPoints = removeDuplicatePt(gridPoints,line,cellWidth,cellHeight,
                    isXCordSwapped,isYCordSwapped);

                /* Add the grid points to this line*/
                line.AddPoints(gridPoints);

                //sort the grid intersect points in the line
                line.SortPoints();

                _populateCell(line, originalGridPts, cellDictionary, isXCordSwapped, isYCordSwapped, cellWidth, cellHeight);
            }
        }

        /* makes a clone */
        List<GridIntersectPoint> clonePts(List<GridIntersectPoint>  gridPoints)
        {
            List<GridIntersectPoint> copyList = new List<GridIntersectPoint>();
            GridIntersectPoint pt;
            
            foreach(var point in gridPoints)
            {
                pt = new GridIntersectPoint(point.X,point.Y);
                pt.setLine(point.getLine());
                copyList.Add(pt);
            }
            return copyList;
        }

        private void getStartEndGridYCordinate(double cellHeight, Point startPt, Point endPt,
            out double startYGridCord, out double endYGridCord,out bool isYCordSwapped)
        {
            isYCordSwapped = false;
            double startYGrid;
            double endYGrid;
            double startY = startPt.getY();
            double endY = endPt.getY();
            Point temp;

            if (startY > endY)
            {
                temp = startPt;
                startPt = endPt;
                endPt = temp;
                isYCordSwapped = true;
            }

            if (_lowerBoundingBox.Y < 0)
            {
                startYGrid = Math.Ceiling((startPt.Y + Math.Abs(_lowerBoundingBox.Y)) / cellHeight);
                startYGridCord = _lowerBoundingBox.Y + (startYGrid * cellHeight);

                endYGrid = Math.Floor((endPt.Y + Math.Abs(_lowerBoundingBox.Y)) / cellHeight);
                endYGridCord = _lowerBoundingBox.Y + endYGrid * cellHeight;
            }
            else
            {
                startYGrid = Math.Ceiling(startPt.Y / cellHeight);
                startYGridCord = startYGrid * cellHeight;

                endYGrid = Math.Floor(endPt.Y / cellHeight);
                endYGridCord = endYGrid * cellHeight;
            }
        }

        private void getStartEndGridXCordinate(double cellWidth, Point startPoint, Point endPoint, 
            out double startXGridCord, out double endXGridCord,out bool isXCordSwapped)
        {
            isXCordSwapped = false;
            Point temp;
            /*swap start and end points*/
            if (startPoint.getX() > endPoint.getX())
            {
                temp = startPoint;
                startPoint = endPoint;
                endPoint = temp;
                isXCordSwapped = true;
            }

            double startX;
            double startXGrid;

            double endX;
            double endXGrid;


            if (_lowerBoundingBox.X < 0)
            {
                startX = startPoint.getX();
                //find the first vertical x-grid to test intersection with line
                startXGrid = Math.Ceiling((startX + Math.Abs(_lowerBoundingBox.X)) / cellWidth);
                startXGridCord = _lowerBoundingBox.X + startXGrid * cellWidth;

                endX = endPoint.getX();
                //find the end vertical x-grid to test intersection
                endXGrid = Math.Floor((endX + Math.Abs(_lowerBoundingBox.X)) / cellWidth);
                endXGridCord = _lowerBoundingBox.X + endXGrid * cellWidth;
            }
            else
            {
                startX = startPoint.getX();
                //find the first vertical x-grid to test intersection with line
                startXGrid = Math.Ceiling(startX / cellWidth);
                startXGridCord = startXGrid * cellWidth;

                endX = endPoint.getX();
                //find the end vertical x-grid to test intersection
                endXGrid = Math.Floor(endX / cellWidth);
                endXGridCord = endXGrid * cellWidth;
            }
        }

        private List<GridIntersectPoint> removeDuplicatePt(List<GridIntersectPoint> gridPts,Line line,
            double cellWidth,double cellHeight, bool isXCordSwapped, bool isYCordSwapped)
        {
            double startXGridCord;
            double endXGridCord;
            double startYGridCord;
            double endYGridCord;

            Point startPt = line.Start, endPt = line.End;

            /* for X grid lines */
            getStartEndGridXCordinate(cellWidth, line.Start, line.End, out startXGridCord,
                out endXGridCord,out isXCordSwapped);

            /* for Y grid lines */
            getStartEndGridYCordinate(cellHeight, line.Start, line.End, out startYGridCord,
                out endYGridCord, out isYCordSwapped);

            if (isXCordSwapped)
            {
                swapPoints(ref startPt, ref endPt);
            }
            if (startPt.X == startXGridCord || startPt.Y == startYGridCord)
                //|| startPt.Y == startYGridCord || startPt.Y == startYGridCord)
            {
                gridPts.RemoveAt(0);
            }


            startPt = line.Start;
            endPt = line.End;

           

            if (isYCordSwapped)
            {
                swapPoints(ref startPt,ref endPt);
            }
            if ((gridPts.Count > 0 ) && (endPt.X == endXGridCord || endPt.Y == endYGridCord))
                   //|| endPt.Y == endXGridCord || endPt.Y == endYGridCord)
            {

                gridPts.RemoveAt(gridPts.Count - 1);
            }
            

            return gridPts;
        }

        private static void swapPoints(ref Point a, ref Point b)
        {
            Point temp = a;
            a = b;
            b = temp;
        }

        private void _addGridLineToCell(Line line, Dictionary<int, ICellable> cellDictionary, bool isXCordSwapped, 
            bool isYCordSwapped, double cellWidth, double cellHeight)
        {
            int cellId;
            ICellable cell;
            //calculate the mid-point
            double midPointX = (line.Start.X + line.End.X) / 2.0;
            double midPointY = (line.Start.Y + line.End.Y) / 2.0;
            cellId = _findCellForLine(midPointX, midPointY, cellWidth, cellHeight);

            if (!cellDictionary.TryGetValue(cellId, out cell))
            {
                var bb = _calculateBoundingBox(cellId, cellWidth, cellHeight, _rowCount, _columnCount);
                cell = new Cell(cellId, cellWidth, cellHeight, bb);
            }

            cell.addLine(line);
            cellDictionary[cellId] = cell;
        }

        private int _findCellForLine(double midPointXCord, double midPointYCord, double cellWidth, double cellHeight)
        {
            int cellId;
            if (_lowerBoundingBox.X < 0)
            {
                midPointXCord = midPointXCord + Math.Abs(_lowerBoundingBox.X);
            }

            if (_lowerBoundingBox.Y < 0)
            {
                midPointYCord = midPointYCord + Math.Abs(_lowerBoundingBox.Y);
            }

            double gridXCord = Math.Ceiling(midPointXCord / cellWidth);
            double gridYCord = midPointYCord / cellHeight;

            cellId = (int)(gridYCord) * _columnCount + (int)gridXCord;
            return cellId;
        }

        private int _findGridCellForLine(double midPointXCord, double midPointYCord, double cellWidth, double cellHeight)
        {
            int cellId;

            if (_lowerBoundingBox.X < 0)
            {
                midPointXCord = midPointXCord + Math.Abs(_lowerBoundingBox.X);
            }

            if (_lowerBoundingBox.Y < 0)
            {
                midPointYCord = midPointYCord + Math.Abs(_lowerBoundingBox.Y);
            }

            double gridXCord = Math.Ceiling(midPointXCord / cellWidth);
            double gridYCord = Math.Floor(midPointYCord / cellHeight);

            cellId = (int)(gridYCord) * _columnCount + (int)gridXCord;
            return cellId;
        }

        private void _populateCell(Line line, List<GridIntersectPoint> gridPoints, Dictionary<int, ICellable> cellDictionary,
           bool isXCordSwapped, bool isYCordSwapped, double cellWidth, double cellHeight)
        {
            int cellId;
            Line gridLine;
            double midPointXCord;
            double midPointYCord;
            List<int> cellIdList = new List<int>();
            ICellable cell;

            Point start = line.Start;
            Point end = line.End;
            Point temp;

            /* swap them */
            if (start.getX() > end.getX())
            {
                temp = line.Start;
                start = line.End;
                end = temp;
            }

            //put the first grid cell segment to the cell
            if (gridPoints != null && gridPoints.Count() > 0)
            {
                //if (false == gridPoints[0].Equals(start))
                if (gridPoints[0].X != start.X || gridPoints[0].Y != start.Y)
                {
                    //calculate midpoint
                    midPointXCord = (start.getX() + gridPoints[0].getX()) / 2.0;
                    midPointYCord = (start.getY() + gridPoints[0].getY()) / 2.0;
                    cellId = _findCellForLine(midPointXCord, midPointYCord, cellWidth, cellHeight);
                    //add to cellId list
                    cellIdList.Add(cellId);
                    Line firstGridLine;
                    if (isXCordSwapped || isYCordSwapped)
                    {
                        firstGridLine = new Line(gridPoints[0], start);
                    }
                    else
                    {
                        firstGridLine = new Line(start, gridPoints[0]);
                    }
                    /* add label to children lines */
                    firstGridLine.label = line.label;

                    if (!cellDictionary.TryGetValue(cellId, out cell))
                    {
                        var bb = _calculateBoundingBox(cellId, cellWidth, cellHeight, _rowCount, _columnCount);
                        cell = new Cell(cellId, cellWidth, cellHeight, bb);
                    }

                    // the parent of this new line inside grid is this line object itself
                    firstGridLine.parent = line;

                    cell.addLine(firstGridLine);
                    /* Add the grid point to the cell*/
                    cell.setGridIntersectPoint(gridPoints, line);
                    cellDictionary[cellId] = cell;
                }
            }
            /*
             *go through each line using GridPoints and  calculate the cell id based on midpoint
             *of the line and populate the cell data structure and the cellDictionary
             */
            for (int count = 0; count < gridPoints.Count() - 1; count++)
            {
                midPointXCord = (gridPoints[count].getX() + gridPoints[count + 1].getX()) / 2.0;
                midPointYCord = (gridPoints[count].getY() + gridPoints[count + 1].getY()) / 2.0;
                cellId = _findGridCellForLine(midPointXCord, midPointYCord, cellWidth, cellHeight);
                //add the cell id to the list
                cellIdList.Add(cellId);

                //create the line in the grid
                if (isXCordSwapped)
                {
                    gridLine = new Line(gridPoints[count + 1], gridPoints[count]);
                }
                else
                {
                    gridLine = new Line(gridPoints[count], gridPoints[count + 1]);
                }
                /* set label to parent label */
                gridLine.label = line.label;

                if (!cellDictionary.TryGetValue(cellId, out cell))
                {
                    var bb = _calculateBoundingBox(cellId, cellWidth, cellHeight, _rowCount, _columnCount);
                    cell = new Cell(cellId, cellWidth, cellHeight, bb);
                }

                // the parent of this new line inside grid is this line object itself
                gridLine.parent = line;
                /* gridpoints list to this method*/
                //List<GridIntersectPoint> gridPts = new List<GridIntersectPoint>();
                //gridPts.Add(gridPoints[count + 1]);
                //gridPts.Add(gridPoints[count]);

                cell.addLine(gridLine);

                /* add gridpoints to the cell */
                cell.setGridIntersectPoint(gridPoints,line);
                cellDictionary[cellId] = cell;
            }


            //check for the last partitioned line
            int numberOfPoints = gridPoints.Count;
            //false == (gridPoints[numberOfPoints - 1].Equals(end))
            bool result = ((gridPoints[numberOfPoints - 1].X == end.X) && (gridPoints[numberOfPoints - 1].Y == end.Y));
            if (numberOfPoints > 0 && (!result))
            {
                midPointXCord = (gridPoints[numberOfPoints - 1].getX() + end.getX()) / 2.0;
                midPointYCord = (gridPoints[numberOfPoints - 1].getY() + end.getY()) / 2.0;
                cellId = _findCellForLine(midPointXCord, midPointYCord, cellWidth, cellHeight);
                //add the cell id to the list
                cellIdList.Add(cellId);

                //create the line in the grid
                Line lastGridLine;
                if (isXCordSwapped)
                {
                    lastGridLine = new Line(end, gridPoints[numberOfPoints - 1]);
                }
                else
                {
                    lastGridLine = new Line(gridPoints[numberOfPoints - 1], end);
                }
                /* set child line's label as parent's label */
                lastGridLine.label = line.label;

                if (!cellDictionary.TryGetValue(cellId, out cell))
                {
                    var bb = _calculateBoundingBox(cellId, cellWidth, cellHeight, _rowCount, _columnCount);
                    cell = new Cell(cellId, cellWidth, cellHeight, bb);
                }

                // the parent of this new line inside grid is this line object itself
                lastGridLine.parent = line;

                /* add grid points to cell*/
                cell.setGridIntersectPoint(gridPoints,line);
                cell.addLine(lastGridLine);
                cellDictionary[cellId] = cell;
            }
            _findCellNeighbours(cellIdList, cellDictionary);
        }

        private Tuple<double, double, double, double> _calculateBoundingBox(int cellId, double cellWidth,
            double cellHeight, int rowCount, int colCount)
        {
            double ymax;
            double xmax = cellId % colCount;
            if (0 == xmax)
            {
                xmax = colCount * cellWidth;
            }
            else
            {
                xmax = xmax * cellWidth;
            }

            if (_lowerBoundingBox.X < 0)
            {
                xmax = _lowerBoundingBox.X + xmax;
            }

            if (_lowerBoundingBox.Y < 0)
            {
                ymax = _lowerBoundingBox.Y + Math.Ceiling((double)cellId / colCount) * cellHeight;
            }
            else
            {
                ymax = Math.Ceiling((double)cellId / colCount) * cellHeight;
            }

            
            double xmin = xmax - cellWidth;
            double ymin = ymax - cellHeight;
            return new Tuple<double, double, double, double>(xmin, xmax, ymin, ymax);
        }

        private void _findCellNeighbours(List<int> cellIdList, Dictionary<int, ICellable> cellDictionary)
        {
            int listSize = cellIdList.Count();
            for (int counter = 0; counter < listSize - 1; counter++)
            {
                _updateNeighbourCellInfo(cellIdList[counter], cellIdList[counter + 1], cellDictionary);
            }
        }

        private void _updateNeighbourCellInfo(int cellId1, int cellId2, Dictionary<int, ICellable> cellDictionary)
        {
            ICellable leftCell;
            ICellable rightCell;
            ICellable upCell;
            ICellable downCell;
            /* horizontal neighbours */
            if (1 == Math.Abs(cellId1 - cellId2))
            {
                /* cellId1 is on the right side of cellId2 */
                if (cellId1 > cellId2)
                {
                    /* update the left-right neighbour information in cell-dictionary */
                    if (true == cellDictionary.ContainsKey(cellId2))
                    {
                        leftCell = cellDictionary[cellId2];
                        leftCell.setRightCell(cellId1);

                        rightCell = cellDictionary[cellId1];
                        rightCell.setLeftCell(cellId2);
                    }
                }
                else /* cell id 2 is on the right of cell id 1 
                         cell id 1 is left*/
                {
                    /* update the left-right neighbour information in cell-dictionary */
                    if (true == cellDictionary.ContainsKey(cellId1))
                    {
                        leftCell = cellDictionary[cellId1];
                        leftCell.setRightCell(cellId2);

                        rightCell = cellDictionary[cellId2];
                        rightCell.setLeftCell(cellId1);
                    }
                }
            } /* vertical neigbours */
            else if (_columnCount == Math.Abs(cellId1 - cellId2))
            {
                /* cellId1 is on the top side of cellId2 */
                if (cellId1 > cellId2)
                {
                    /* update the top-bottom neighbour information in cell-dictionary */
                    if (true == cellDictionary.ContainsKey(cellId2))
                    {
                        downCell = cellDictionary[cellId2];
                        downCell.setTopCell(cellId1);

                        upCell = cellDictionary[cellId1];
                        upCell.setBottomCell(cellId2);
                    }
                }
                else /* cell id 2 is the top side of cell id 1 */
                {
                    /* update the top-bottom neighbour information in cell-dictionary */
                    if (true == cellDictionary.ContainsKey(cellId1))
                    {
                        downCell = cellDictionary[cellId1];
                        downCell.setTopCell(cellId2);

                        upCell = cellDictionary[cellId2];
                        upCell.setBottomCell(cellId1);
                    }
                }
            }

        }

        /// <summary>
        /// Calculates the dimensions of the Cell for the Uniform Grid
        /// </summary>
        /// <param name="layer1">layer 1</param>
        /// <param name="layer2">layer 2</param>
        /// <returns>returns the tuple of (cellWidth, cellHeight)</returns>
        private Tuple<double, double> _calculateDimensions(Layer layer1, Layer layer2)
        {
            Debug.Assert(layer1 != null);
            Debug.Assert(layer2 != null);

            List<Point> ptLayer1 = layer1.GetBoundingBox();
            List<Point> ptLayer2 = layer2.GetBoundingBox();

            double width, height;
            double minX = Math.Min(ptLayer1[0].X, ptLayer2[0].X);
            double minY = Math.Min(ptLayer1[0].Y, ptLayer2[0].Y);

            double maxX = Math.Max(ptLayer1[1].X, ptLayer2[1].X);
            double maxY = Math.Max(ptLayer1[1].Y, ptLayer2[1].Y);
            /* relative to zero */
            if (minX > 0)
            {
                width = maxX;
            }
            else
            {
                width = maxX - minX;
            }

            if (minY > 0)
            {
                height = maxY;
            }
            else
            {
                height = maxY - minY;
            }

            double cellWidth = width / (double)_columnCount;
            double cellHeight = height / (double)_rowCount;

            //we need to calculate the cell width and cell height here
            _lowerBoundingBox = new Point(minX, minY);
            return new Tuple<double, double>(cellWidth, cellHeight); // width, height
        }

        #region merging code
        /*
        public void merge(Cell [,] cells,int row,int column)
        {
            int i, j, k;
            int a,b;
            for (i = 0; i <= row - 1; i++)
            {
                for (j = 0; j <= column - 1; j++)
                {

                    for (k = 0; k < cells[i, j].postPolys.Count; k++)
                    {
                        _postPolygons.Add(cells[i, j].postPolys[k]);
                    }

                }
            }

            for (i = 0; i <= row - 1; i++)
            {
                for (j = 0; j <= column - 2; j++)
                {
                    if (cells[i, j].rightLinkedPoints.Count != 0)
                    {
                        for (a=0;a<cells[i, j].rightLinkedPoints.Count;a++) 
                        {
                            for (b = 0; b <cells[i, j+1].leftLinkedPoints.Count; b++) 
                            {
                                LinkedPoint p = cells[i, j].rightLinkedPoints[a];
                                LinkedPoint p1 = cells[i, j+1].leftLinkedPoints[b];
                                LinkedPoint p2 = null;
                                LinkedPoint p3 = null;
                                if (p.getPoint().Equals(p1.getPoint()))
                                {
                                    cells[i, j].rightLinkedPoints.Remove(p);
                                    cells[i, (j + 1)].leftLinkedPoints.Remove(p1);

                                    
                                    if (p.getNext().getPoint() is VirtualIntersectPoint)
                                    {
                                        p2 = p.getNext();
                                        p3 = p1.getPre();
                                        p.setNext(p1.getNext());
                                        p1.getNext().setPre(p);
                                        p2.setPre(p3.getPre());
                                        p3.getPre().setNext(p2);
                                        cells[i, j].rightLinkedPoints.Remove(p2);
                                        cells[i, (j + 1)].leftLinkedPoints.Remove(p3);

                                    }
                                    else
                                    {
                                        p2 = p.getPre();
                                        p3 = p1.getNext();
                                        p.setPre(p1.getPre());
                                        p1.getPre().setNext(p);
                                        p2.setNext(p3.getNext());
                                        p3.getNext().setPre(p2);
                                        cells[i, j].rightLinkedPoints.Remove(p2);
                                        cells[i, (j + 1)].leftLinkedPoints.Remove(p3);
                                    }
                                    _postPolygons.Remove(p1.getPostPolygon());
                                }
                            }
                        }
                    }
                     if (cells[i, j].downLinkedPoints.Count != 0)
                    {
                        for (a=0;a<cells[i, j].downLinkedPoints.Count;a++) 
                        {
                            for (b = 0; b < cells[i, j+1].upLinkedPoints.Count; b++) 
                            {
                                LinkedPoint p = cells[i, j].downLinkedPoints[a];
                                LinkedPoint p1 = cells[i, j+1].upLinkedPoints[b];
                                LinkedPoint p2 = null;
                                LinkedPoint p3 = null;
                                if (p.getPoint().Equals(p1.getPoint()))
                                {
                                    cells[i, j].downLinkedPoints.Remove(p);
                                    cells[i, (j + 1)].upLinkedPoints.Remove(p1);

                                    
                                    if (p.getNext().getPoint() is VirtualIntersectPoint)
                                    {
                                        p2 = p.getNext();
                                        p3 = p1.getPre();
                                        p.setNext(p1.getNext());
                                        p1.getNext().setPre(p);
                                        p2.setPre(p3.getPre());
                                        p3.getPre().setNext(p2);
                                        cells[i, j].downLinkedPoints.Remove(p2);
                                        cells[i, (j + 1)].upLinkedPoints.Remove(p3);

                                    }
                                    else
                                    {
                                        p2 = p.getPre();
                                        p3 = p1.getNext();
                                        p.setPre(p1.getPre());
                                        p1.getPre().setNext(p);
                                        p2.setNext(p3.getNext());
                                        p3.getNext().setPre(p2);
                                        cells[i, j].downLinkedPoints.Remove(p2);
                                        cells[i, (j + 1)].upLinkedPoints.Remove(p3);
                                    }
                                    _postPolygons.Remove(p1.getPostPolygon());
                                }
                            }
                        }
                    }
                    }
                }

                for (i = 0; i < _postPolygons.Count; i++)
                {
                    Console.WriteLine(_postPolygons[i].ToString());
                }
                //if (cells[i, (_columntCount - 1)].downPoints.Count != 0)
                //{
                //}
            }
         */
        #endregion
    }
}
